package com.binest.task.service.impl;

import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.binest.common.constant.ChainConstants;
import com.binest.common.utils.ChainUtils;
import com.binest.inclusionExamine.domain.InclusionExamine;
import com.binest.inclusionExamine.service.IInclusionExamineService;
import com.binest.system.service.ISysConfigService;
import com.binest.task.service.ITaskService;
import com.binest.votingRecords.domain.VotingRecords;
import com.binest.votingRecords.service.IVotingRecordsService;
import org.bouncycastle.util.encoders.Hex;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.web3j.protocol.core.methods.response.EthBlock;
import org.web3j.utils.Convert;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;

/**
 * @ClassName: TaskServiceImpl
 * @Description:
 * @Author
 * @Date 2024/3/4
 * @Version 1.0
 */
@Service
public class TaskServiceImpl implements ITaskService {
    @Autowired
    ISysConfigService sysConfigService;
    @Autowired
    IVotingRecordsService votingRecordsService;
    @Autowired
    IInclusionExamineService inclusionExamineService;
    @Autowired
    RedisTemplate<String,String> redisTemplate;
    @Override
    public void approveTask() throws IOException {
        Map logMap = readChainInfo(ChainConstants.APPROVE_BLOCK_HEIGHT_KEY,ChainUtils.APPROVE_TOPIC);
        if(logMap!=null){
            BigInteger scanLastBlock = new BigInteger(logMap.get("scanLastBlock").toString());
            System.out.println(">>>>>>>>>>>>"+scanLastBlock);
            JSONArray transferResult = (JSONArray) logMap.get("result");
            JSONObject record = null;
            String data = null;
            for (int i = 0; i < transferResult.size(); i++) {
                record = (JSONObject) transferResult.get(i);
                data = record.getString("data");
                String blockHash= record.getString("blockHash");
                String time= getBlockTimeByBlockHash(blockHash);
                System.out.println(data);
                //单据类型 orderType : 1:项目 2:人物,3:机构,4:,5:。
                BigInteger orderType =new BigInteger(StringUtils.isEmpty(data.substring(26,66))?"0":data.substring(26,66),16);
                //审核人地址
                String auditorAddress = "0x"+data.substring(67,130).replaceAll("^(0+)","");
                String approveStatusStr = data.substring(131,194);
                //审核状态:1:审核通过，2：审核拒绝
                BigInteger approveStatus =new BigInteger(StringUtils.isEmpty(approveStatusStr)?"0":approveStatusStr,16);
                //主ID
                String mainId = new String(Hex.decode(data.substring(386,450).getBytes(StandardCharsets.UTF_8)));
                //ipfs hash
                String qmHash = new String(Hex.decode(data.substring(514,606).getBytes(StandardCharsets.UTF_8)));

                System.out.println("单据类型："+orderType);
                System.out.println("审核人："+auditorAddress);
                System.out.println("审核状态："+approveStatus);
                System.out.println("主ID:"+mainId);
                System.out.println("ipfs hash:"+qmHash);
                //TODO 如果qmHash不存在我们的数据库中，说明被人作弊，记录到一个表中，后续发起投票，把审核人资产扣掉
                InclusionExamine inclusionExamine=new InclusionExamine();
                inclusionExamine.setQmHash(qmHash);
                List<InclusionExamine>  list=   inclusionExamineService.selectInclusionExamineList(inclusionExamine);
                //如果为空则作弊
                if(list.size()==0||list==null){
                    VotingRecords votingRecords =new VotingRecords();
                    votingRecords.setQmHash(qmHash);
                    votingRecords.setApproveStatus(approveStatus.toString());
                    votingRecords.setAuditorAddress(auditorAddress);
                    if(orderType.toString().equals("1")||orderType.toString().equals("0")){
                        votingRecords.setOrderType("0");
                    }else if(orderType.toString().equals("2")){
                        votingRecords.setOrderType("1");
                    }else if(orderType.toString().equals("3")){
                        votingRecords.setOrderType("2");
                    }else if(orderType.toString().equals("4")){
                        votingRecords.setOrderType("3");
                    }else if(orderType.toString().equals("5")){
                        votingRecords.setOrderType("4");
                    }else if(orderType.toString().equals("6")){
                        votingRecords.setOrderType(orderType.toString());
                    }else if(orderType.toString().equals("7")){
                        votingRecords.setOrderType(orderType.toString());
                    }
                    votingRecords.setMainId(mainId);
                    votingRecordsService.insertVotingRecords(votingRecords);

                }else {
                    //审核通过
                    if(approveStatus.toString().equals("1")){

                        //更新数据库
                        inclusionExamineService.updateStatusByHash(qmHash,"1");
                        InclusionExamine  ex=new InclusionExamine();
                        ex.setQmHash(qmHash);
                        ex.setId(list.get(0).getId());
                        ex.setStatus(approveStatus.toString());
                        ex.setExamineTime(Long.valueOf(time));

                        if(orderType.toString().equals("1")||orderType.toString().equals("0")){
                            ex.setType("0");
                        }else if(orderType.toString().equals("2")){
                            ex.setType("1");
                        }else if(orderType.toString().equals("3")){
                            ex.setType("2");
                        }else if(orderType.toString().equals("4")){
                            ex.setType("3");
                        }else if(orderType.toString().equals("5")){
                            ex.setType("4");
                        }else if(orderType.toString().equals("6")){
                            ex.setType(orderType.toString());
                        }else if(orderType.toString().equals("7")){
                            ex.setType(orderType.toString());
                        }
//                        ex.setType(orderType.toString());
                        ex.setProjectId(list.get(0).getProjectId());
                        try {
                            ex.setAddress(auditorAddress);
                            inclusionExamineService.examine(ex);
                            InclusionExamine oldInclusionExamine = list.get(0);
                            if(!StringUtils.isEmpty(oldInclusionExamine.getOldId())){
                                //更新对外投资等数据
                                inclusionExamineService.updateApproveAfterData(oldInclusionExamine.getOldId(),oldInclusionExamine.getProjectId());

                            }

                        } catch (Exception e) {
                            throw new RuntimeException(e);
                        }


                    }else if(approveStatus.toString().equals("2")){
                        inclusionExamineService.updateStatusByHash(qmHash,"2");
                    }
                }

            }
            //最后更新扫描高度scanLastBlock 到sysConfig (ChainConstants.APPROVE_BLOCK_HEIGHT_KEY);
            sysConfigService.updateConfigValueByKey(ChainConstants.APPROVE_BLOCK_HEIGHT_KEY,String.valueOf(scanLastBlock));

        }
    }

    private String getBlockTimeByBlockHash(String blockHash) throws IOException {
        String rs = redisTemplate.opsForValue().get("hash:"+blockHash);
        if(!StringUtils.isEmpty(rs)){
            return rs;
        }
        EthBlock ethBlock =  ChainUtils.getWeb3j().ethGetBlockByHash(blockHash,false).send();
        if(ethBlock!=null&&!ethBlock.hasError()){
            rs = String.valueOf(ethBlock.getBlock().getTimestamp());
            redisTemplate.opsForValue().set("hash:"+blockHash,rs);
        }
        return rs;
    }
    @Override
    public void claimTask() {
        Map logMap = readChainInfo(ChainConstants.CLAIM_BLOCK_HEIGHT_KEY,ChainUtils.CLAIM_TOPIC);
        if(logMap!=null){
            BigInteger scanLastBlock = new BigInteger(logMap.get("scanLastBlock").toString());
            System.out.println(">>>>>>>>>>>>"+scanLastBlock);
            JSONArray transferResult = (JSONArray) logMap.get("result");
            JSONObject record = null;
            String data = null;
            for (int i = 0; i < transferResult.size(); i++) {

                record = (JSONObject) transferResult.get(i);
                data = record.getString("data");
                System.out.println(data);
                //单子类型 orderType : 1:项目 2:人物,3:机构,4:,5:。
                BigInteger orderType =new BigInteger(StringUtils.isEmpty(data.substring(26,66))?"0":data.substring(26,66),16);
                //触发人地址
                String claimAddress = "0x"+data.substring(67,130).replaceAll("^(0+)","");
                String statusStr = data.substring(258,322);
                //单据状态：2:审核通过，4：申诉成功 5:申诉失败，7：投票成功，8：投票失败
                BigInteger status =new BigInteger(StringUtils.isEmpty(statusStr)?"0":statusStr,16);
                //主ID
                String mainId = new String(Hex.decode(data.substring(450,514).getBytes(StandardCharsets.UTF_8)));
                //ipfs hash
                String qmHash = new String(Hex.decode(data.substring(578,670).getBytes(StandardCharsets.UTF_8)));
                String mintAmountStr = data.substring(196,258);
                BigInteger mintAmountInt =new BigInteger(StringUtils.isEmpty(mintAmountStr)?"0":mintAmountStr,16);
                BigDecimal mintAmount = Convert.fromWei(mintAmountInt.toString(), Convert.Unit.ETHER);
                System.out.println("单据类型："+orderType);
                System.out.println("触发人："+claimAddress);
                System.out.println("单据状态："+status);
                System.out.println("主ID:"+mainId);
                System.out.println("ipfs hash:"+qmHash);
                System.out.println("产生Wiki数量:"+mintAmount);
                //// TODO: 2024/3/5 处理领取后的单据状态
                //如果单据是申诉成功 status=4 ，要像审核通过一样把这个qmHash更新为最新的展示给用户，同时标注 奖励已领取
                //如果申诉失败 就标记为申诉失败就可以 同时也标注为 无奖励
                //如果是7：投票成功，此时这个qmHash正好是给用户展示
                // 的要给他撤回来并展示上一条最新的数据给用户，并且标记为 无法领取奖励
                //如果是8：投票失败，只标注为 已领取奖励
                //判断状态
                //审核通过
                if(status.toString().equals("1")){
                    inclusionExamineService.updateStatusByHash(qmHash,"1");
                    inclusionExamineService.updateClaimStatus(qmHash,"0");

                } else if (status.toString().equals("2")) {
                    inclusionExamineService.updateClaimStatus(qmHash,"1");
                }

            }
            //最后更新扫描高度scanLastBlock 到sysConfig (ChainConstants.CLAIM_BLOCK_HEIGHT_KEY); 上线记得放开下面的
           sysConfigService.updateConfigValueByKey(ChainConstants.CLAIM_BLOCK_HEIGHT_KEY,String.valueOf(scanLastBlock));
        }
    }

    private Map readChainInfo(String blockHeightKey,String topic){
        try {
            String lastBlockStr = sysConfigService.selectConfigByKeyNoCache(blockHeightKey);
            BigInteger currentBlock = ChainUtils.getWeb3j().ethBlockNumber().send().getBlockNumber();
            BigInteger lastBlock = BigInteger.valueOf(Long.valueOf(lastBlockStr));
            BigInteger scanLastBlock = currentBlock;
            if (lastBlock.add(ChainUtils.scanSpace).compareTo(currentBlock) < 0) {
                scanLastBlock = lastBlock.add(ChainUtils.scanSpace);
            } else if (lastBlock.compareTo(scanLastBlock) >= 0) {
                System.out.println("扫描从:" + lastBlock + ",到：" + scanLastBlock + "高度不够下次再扫");
                return null;
            }
            System.out.println("扫描从:" + lastBlock + ",到：" + scanLastBlock);

            String fromBlock = lastBlock.toString(16);
            String toBlock = scanLastBlock.subtract(BigInteger.ONE).toString(16);
            String transferLogs = requestGetLog(ChainUtils.getNodeURL(), ChainUtils.getPlayerContract(), fromBlock, toBlock, topic);
            Map logMap = JSONObject.parseObject(transferLogs, Map.class);
            if (logMap.get("error") != null) {
                System.out.println(logMap.get("error"));
                throw new Exception(logMap.get("error")+"");
            }
            logMap.put("scanLastBlock",scanLastBlock);
            return logMap;
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }
    @Autowired
    private RestTemplate restTemplate;
    private static final HttpHeaders headers = new HttpHeaders();
    static {
        headers.add("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36");
        headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
    }
    private String requestGetLog(String nodeUrl, String contractAddress, String fromBlockNumber, String toBlockNumber, String topic) {
        String jsonData = "{\"jsonrpc\":\"2.0\",\"method\":\"eth_getLogs\",\"params\":[{\"address\":\"" + contractAddress + "\",\"fromBlock\": \"0x" + fromBlockNumber + "\",\"toBlock\":\"0x" + toBlockNumber + "\",\"topics\":[\"" + topic + "\"]}],\"id\":1}";
        HttpEntity<String> request = new HttpEntity<>(jsonData, headers);
        try {
            ResponseEntity<String> postForEntity = restTemplate.postForEntity(nodeUrl, request, String.class);
            return postForEntity.getBody();
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }
    }

    public static void main(String[] args) {
/*
        String s = "516d596570364e32376a35356979696b4853636d776e7a765a477339486634314473546363536577336867396f76";
        s = "203164373632373233373663333433633939626661316238623563616430616164";
        s = "206536376434376438373431633463626138636130313962313638396439353062";
        byte[]  ff = Hex.decode(s.getBytes(StandardCharsets.UTF_8));
        System.out.println(new String(ff));
*/
        String data="0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000aab2258da14c922298ce9776845a0c47ac764e9200000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000203164373632373233373663333433633939626661316238623563616430616164000000000000000000000000000000000000000000000000000000000000002e516d596570364e32376a35356979696b4853636d776e7a765a477339486634314473546363536577336867396f76000000000000000000000000000000000000";
        String type = data.substring(26,66);
        BigInteger approveType =new BigInteger(StringUtils.isEmpty(type)?"0":type,16);
        //approveType : 0:project ,1: 2:,3:,4:,5:。
        /*System.out.println(approveType);*/
        //审核人地址
        String auditorAddress = "0x"+data.substring(67,130).replaceAll("^(0+)","");
        String approveStatusStr = data.substring(258,322);
        //审核状态:1:审核通过，2：审核拒绝
        BigInteger approveStatus =new BigInteger(StringUtils.isEmpty(approveStatusStr)?"0":approveStatusStr,16);
        //主ID
        String mainId = new String(Hex.decode(data.substring(450,514).getBytes(StandardCharsets.UTF_8)));
        /*System.out.println(data.substring(258,322));*/
        //ipfs hash
        String qmHash = new String(Hex.decode(data.substring(578,670).getBytes(StandardCharsets.UTF_8)));



        System.out.println(data.substring(578,670));
        System.out.println("审批类型："+approveType);
        System.out.println("审核人："+auditorAddress);
        System.out.println("审核状态："+approveStatus);
        System.out.println("主ID:"+mainId);
        System.out.println("ipfs hash:"+qmHash);

        String mintAmountStr = data.substring(196,258);

        BigInteger mintAmountInt =new BigInteger(StringUtils.isEmpty(mintAmountStr)?"0":mintAmountStr,16);
        BigDecimal mintAmount = Convert.fromWei(mintAmountInt.toString(), Convert.Unit.ETHER);

        System.out.println("mint amount:"+mintAmount);

    }
}
